package com.poopinggames.juego1;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Align;
import android.graphics.Paint.Style;
import android.graphics.Rect;

public class PiezaMovible {
	private static final String TAG = "PiezaMovible";
	public boolean selected = false;
	public int x;
	public int y;
	public int width;
	public int height;
	public MyFloat leftX = new MyFloat(x - width / 2);
	public MyFloat rightX = new MyFloat(x + width / 2);
	public MyFloat topY = new MyFloat(y - height / 2);
	public MyFloat bottomY = new MyFloat(y + height / 2);
	public int number = 0;

	public float weight;
	public boolean movible;
	public float movilidad = 1;

	public Border borderLeft;
	public Border borderRight;
	public Border borderTop;
	public Border borderBottom;

	public int id;
	public static ArrayList<PiezaMovible> piezasList = new ArrayList<PiezaMovible>();
	public static PiezaMovible activePieza = null;
	private static int count = 0;

	private int color = Color.GREEN;
	private int textColor = Color.BLACK;

	public PiezaMovible(int number, int x, int y, int width,
			int height, boolean movible) {
		this();
		this.number = number;
		this.x = x;
		this.y = y;
		this.width = width;
		this.height = height;
		this.movible = movible;
		updateMove();

	}

	public PiezaMovible() {
		id = count;
		count++;
		borderLeft = new Border(Tipo.LEFT);
		borderRight = new Border(Tipo.RIGHT);
		borderTop = new Border(Tipo.TOP);
		borderBottom = new Border(Tipo.BOTTOM);

		piezasList.add(this);

	}

	private void updateMove() {
		leftX.value = x - width / 2;
		rightX.value = x + width / 2;
		topY.value = y - height / 2;
		bottomY.value = y + height / 2;

	}

	public static void drawAll(Canvas canvas) {
		for (int i = 0; i < piezasList.size(); i++) {
			piezasList.get(i).drawMe(canvas);
		}
	}

    public static void snapAll(int[] xSnap, int[] ySnap, int tol) {
        for (PiezaMovible pieza : piezasList) {
            for (int i = 0; i < xSnap.length; i++) {
                for (int j = 0; j < ySnap.length; j++) {
                    if (pieza.x - xSnap[i] < tol && pieza.x - xSnap[i] >=-tol
                            && pieza.y - ySnap[j] < tol && pieza.y - ySnap[j] >=-tol) {
                        pieza.x = xSnap[i];
                        pieza.y = ySnap[j];
                        pieza.updateMove();
                    }
                }
            }

        }
    }
    public static void snapAll(List<Integer[]> posList, int tol) {
        for (PiezaMovible pieza : piezasList) {
            for (Integer[] pos :posList){
                if (pieza.x - pos[0] < tol && pieza.x - pos[0] >=-tol
                        && pieza.y - pos[1] < tol && pieza.y - pos[1] >=-tol) {
                    pieza.x = pos[0];
                    pieza.y = pos[1];
                    pieza.updateMove();
                }
            }
        }
    }

    public void drawMe(Canvas canvas) {
		final int rectThick = (int) height / 20;
		final int dThick = (int) rectThick / 2;
		Rect r = new Rect((int) leftX.value, (int) topY.value,
				(int) rightX.value, (int) bottomY.value);
		Rect rBorder = new Rect((int) leftX.value + dThick, (int) topY.value
				+ dThick, (int) rightX.value - dThick, (int) bottomY.value
				- dThick);

		Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
		paint.setStyle(Paint.Style.FILL);
		if (movible) {
			paint.setColor(Color.GREEN);
		} else {
			paint.setColor(Color.GRAY);
		}

		paint.setTextSize(height / 2);

		canvas.drawRect(r, paint);
		if (selected) {
			paint.setStyle(Paint.Style.STROKE);
			paint.setColor(Color.BLACK);
			paint.setStrokeWidth(rectThick);
			canvas.drawRect(rBorder, paint);
		}

		if (movible) {

			paint.setColor(textColor);
			paint.setStrokeWidth(1);
			paint.setTextAlign(Align.CENTER);
			paint.setStyle(Style.FILL);
			canvas.drawText("" + number, x, y + paint.getTextSize() / 2, paint);
		}
	}

	public Map<Integer, Integer> chechColisionDanger(Tipo tipo, int dc) {
		Map<Integer, Integer> tree = new HashMap<Integer, Integer>();
		ValueComparator comparator = new ValueComparator(tree);
		Map<Integer, Integer> treeSorted = new TreeMap<Integer, Integer>(comparator);
		Rango rango1;
		switch (tipo) {
		case RIGHT:
			rango1 = new Rango(borderRight.maxCoord.value,
					borderRight.minCoord.value);
			for (int i = 0; i < piezasList.size(); i++) {
				PiezaMovible pieza = piezasList.get(i);
				Rango rango2 = new Rango(pieza.borderLeft.maxCoord.value,
						pieza.borderLeft.minCoord.value);
				if (i != id) {
					if (rango1.intersection(rango2)) {
						int dist = pieza.borderLeft.commonCoord.value
								- borderRight.commonCoord.value;
						if (dist >= 0 && dist < dc) {
							tree.put(i, dist);
						}

					}

				}
			}
			break;
		case LEFT:
			rango1 = new Rango(borderLeft.maxCoord.value,
					borderLeft.minCoord.value);
			for (int i = 0; i < piezasList.size(); i++) {
				PiezaMovible pieza = piezasList.get(i);
				Rango rango2 = new Rango(pieza.borderRight.maxCoord.value,
						pieza.borderRight.minCoord.value);
				if (i != id) {
					if (rango1.intersection(rango2)) {
						int dist = pieza.borderRight.commonCoord.value
								- borderLeft.commonCoord.value;
						if (dist <= 0 && dist > dc) {
							tree.put(i, dist);
						}
					}

				}
			}
			break;
		case BOTTOM:
			rango1 = new Rango(borderBottom.maxCoord.value,
					borderBottom.minCoord.value);
			for (int i = 0; i < piezasList.size(); i++) {
				PiezaMovible pieza = piezasList.get(i);
				Rango rango2 = new Rango(pieza.borderTop.maxCoord.value,
						pieza.borderTop.minCoord.value);
				if (i != id) {
					if (rango1.intersection(rango2)) {
						int dist = pieza.borderTop.commonCoord.value
								- borderBottom.commonCoord.value;
						if (dist >= 0 && dist < dc) {
							tree.put(i, dist);
						}

					}

				}
			}
			break;
		case TOP:
			rango1 = new Rango(borderTop.maxCoord.value,
					borderTop.minCoord.value);
			for (int i = 0; i < piezasList.size(); i++) {
				PiezaMovible pieza = piezasList.get(i);
				Rango rango2 = new Rango(pieza.borderBottom.maxCoord.value,
						pieza.borderBottom.minCoord.value);
				if (i != id) {
					if (rango1.intersection(rango2)) {
						int dist = pieza.borderBottom.commonCoord.value
								- borderTop.commonCoord.value;
						if (dist <= 0 && dist > dc) {
							tree.put(i, dist);
						}
					}

				}
			}
			break;

		}
		treeSorted.putAll(tree);
		return treeSorted;

	}

	public void moveMe(int dx, int dy) {
		moveMeX(checkMoveMeX(dx));
		moveMeY(checkMoveMeY(dy));

	}

	public Integer checkMoveMeX(int dx) {
		Map<Integer, Integer> treeX;
		ArrayList<Integer> maxDesp = new ArrayList<Integer>();
		if (dx > 0) {
			treeX = chechColisionDanger(Tipo.RIGHT, dx);
		} else {
			treeX = chechColisionDanger(Tipo.LEFT, dx);
		}
		for (Map.Entry<Integer, Integer> entry : treeX.entrySet()) {
			int id = entry.getKey();
			int dist = entry.getValue();
			PiezaMovible pieza = piezasList.get(id);
			if (pieza.movible == false) {
				maxDesp.add(dist);
			} else {
				maxDesp.add(pieza.checkMoveMeX(dx - dist) + dist);
			}

		}
		if (dx > 0) {
			if (maxDesp.size() > 0) {
				Collections.sort(maxDesp);
				return maxDesp.get(0);
			} else {
				return dx;
			}
		} else {
			if (maxDesp.size() > 0) {
				Collections.sort(maxDesp);
				return maxDesp.get(maxDesp.size() - 1);
			} else {
				return dx;
			}
		}

	}

	public Integer checkMoveMeY(int dx) {
		Map<Integer, Integer> treeX;
		ArrayList<Integer> maxDesp = new ArrayList<Integer>();
		if (dx > 0) {
			treeX = chechColisionDanger(Tipo.BOTTOM, dx);
		} else {
			treeX = chechColisionDanger(Tipo.TOP, dx);
		}
		for (Map.Entry<Integer, Integer> entry : treeX.entrySet()) {
			int id = entry.getKey();
			int dist = entry.getValue();
			PiezaMovible pieza = piezasList.get(id);
			if (pieza.movible == false) {
				maxDesp.add(dist);
			} else {
				maxDesp.add(pieza.checkMoveMeY(dx - dist) + dist);
			}

		}
		if (dx > 0) {
			if (maxDesp.size() > 0) {
				Collections.sort(maxDesp);
				return maxDesp.get(0);
			} else {
				return dx;
			}
		} else {
			if (maxDesp.size() > 0) {
				Collections.sort(maxDesp);
				return maxDesp.get(maxDesp.size() - 1);
			} else {
				return dx;
			}
		}

	}

	public boolean checkOnClick(int x, int y) {
		return (x >= this.x - width / 2 && x <= this.x + width / 2
				&& y >= this.y - height / 2 && y <= this.y + height / 2) ? true
				: false;

	}

	public static void moveActivePieza(int dx, int dy) {
		if (activePieza != null) {
			activePieza.moveMe(dx, dy);
		}
	}

	public static void getActivePieza(int x, int y) {
		for (PiezaMovible pieza : piezasList) {
            if (pieza.movible) {
                if (pieza.checkOnClick(x, y)) {
                    // Log.d(TAG, "pieza " + i + " fue tocada en x=" + x + " , y=" +
                    // y);
                    activePieza = pieza;
                    pieza.selected = true;
                    return;
                }
            }

		}
		activePieza = null;

	}

	public static void deselectAll() {
		for (PiezaMovible pieza : piezasList) {
			pieza.selected = false;
			activePieza = null;
		}
	}

	public void moveMeX(int dx) {
		Map<Integer, Integer> treeX;
		ArrayList<Integer> maxDesp = new ArrayList<Integer>();
		if (dx > 0) {
			treeX = chechColisionDanger(Tipo.RIGHT, dx);
		} else {
			treeX = chechColisionDanger(Tipo.LEFT, dx);
		}
		for (Map.Entry<Integer, Integer> entry : treeX.entrySet()) {
			int id = entry.getKey();
			int dist = entry.getValue();
			PiezaMovible pieza = piezasList.get(id);
			pieza.moveMeX(pieza.checkMoveMeX(dx - dist));
		}

		x += dx;
		updateMove();
	}

	public void moveMeY(int dx) {
		Map<Integer, Integer> treeX;
		ArrayList<Integer> maxDesp = new ArrayList<Integer>();
		if (dx > 0) {
			treeX = chechColisionDanger(Tipo.BOTTOM, dx);
		} else {
			treeX = chechColisionDanger(Tipo.TOP, dx);
		}
		for (Map.Entry<Integer, Integer> entry : treeX.entrySet()) {
			int id = entry.getKey();
			int dist = entry.getValue();
			PiezaMovible pieza = piezasList.get(id);
			pieza.moveMeY(pieza.checkMoveMeY(dx - dist));

		}

		y += dx;
		updateMove();

	}

	class Border {
		public MyFloat commonCoord;
		public MyFloat maxCoord;
		public MyFloat minCoord;
		private Tipo tipo;

		public Border(MyFloat commonCoord, MyFloat maxCoord, MyFloat minCoord) {
			this.commonCoord = commonCoord;
			this.maxCoord = maxCoord;
			this.minCoord = minCoord;
		}

		public Border(Tipo tipo) {
			this.tipo = tipo;
			switch (this.tipo) {
			case LEFT:
				this.commonCoord = leftX;
				this.maxCoord = topY;
				this.minCoord = bottomY;
				break;
			case RIGHT:
				this.commonCoord = rightX;
				this.maxCoord = topY;
				this.minCoord = bottomY;
				break;
			case TOP:
				this.commonCoord = topY;
				this.maxCoord = rightX;
				this.minCoord = leftX;
				break;
			case BOTTOM:
				this.commonCoord = bottomY;
				this.maxCoord = rightX;
				this.minCoord = leftX;
				break;
			}
		}

	}

}
